/******************************************************************************************
Copyright(C), 2019-2021, 个人。
文件名：L_RTP.h
作者：Wind    版本：V1.0    日期：2020.4.1
文件描述：
    头文件。
历史修改记录：
1. 2020-4-1:Wind
创建。

2. 2021-6-19:Wind
修改格式以向实验室开放。
******************************************************************************************/

#ifndef L_RTP__
#define L_RTP__

//+------------------------------------------------------------------------------------------+
//|                                         头文件包含
//+------------------------------------------------------------------------------------------+
/*|*/#include <net/if.h>
/*|*/#include <sys/socket.h>
/*|*/#include <netinet/in.h>
//+------------------------------------------------------------------------------------------+
//|                                           宏定义
//+------------------------------------------------------------------------------------------+
//|  ------------------------------------------------------------
//|  RTP分包大小
//|  此处的分包大小是针对剔除了RTP头和NALU头的数据流而言的。
//|  RTP分包理论上也可以交给传输层的UDP协议去做，但由于网络环境的
//|  复杂和不可预知，有可能导致传输层协议的分包出现错误，在路由拥
//|  塞的时候更是如此，为了尽可能避免这样的事情发生，采用在应用层
//|  分包的策略，发送之前将RTP报文截断为不超过一个UDP报文的大小，
//|  这样可以有效缓解传输中的不确定性带来的影响，RTP分片也是为此
//|  而生的。
//|  然而这样做的时候，如果传输中发生包的丢失，RTP依旧无法处理，只
//|  能丢弃，这也体现了RTP不保证服务质量这一特点。
//|  ------------------------------------------------------------
/*|*/#define RTP_H264_PACKAGE_LENGTH 1400
//|  ------------------------------------------------------------
//|  RTP头部的荷载码
//|  ------------------------------------------------------------
/*|*/#define RTP_HEAD_PAYLOAD_H264 96
/*|*/#define RTP_HEAD_PAYLOAD_G711 97
//+------------------------------------------------------------------------------------------+
//|                                           数据类型
//+------------------------------------------------------------------------------------------+
//|  ------------------------------------------------------------
//|                              RTP协议头
//|  |-----byte 0----|-----byte 1----|-----byte 2----|-----byte 3----|
//|   0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
//|  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|  |V=2|P|X|  CC   |M|     PT      |            序列号             |
//|  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|  |                             时间戳                            |
//|  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|  |                       同步源(SSRC)标识符                      |
//|  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//|  |                       贡献源(CSRC)标识符                      |
//|  |                             ····                              |
//|  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|  可以看出，在此官方规定中，是以大端方式进行定义的。
//|  大小端针对的基本单位是字节。是对本机存储的方式而言的。
//|  一个16位short型的数据，大端和小端也是分高8位和低8位进行存储的。
//|  实际RTP传输中，RTP头作为UDP报文中的一部分，是以无格式字节流进行传输的。
//|  在大端模式处理器下，位段的顺序V、P、X、CC与之对应。
//|  在小端模式处理器下，位段的顺序CC、X、P、V与之对应。
//|  在C标准中，位段的数据类型只能是int或者unsigned int（C99/C11中增加了_Bool类型），
//|  使用其他的数据类型可能是不被允许或者未定义的。
//|  ---------------------以下的定义中是以小端模式实现的---------------------
//|  学习参考：https://blog.csdn.net/mo4776/article/details/82319084
//|  学习参考：https://www.itranslater.com/qa/details/2582479752443462656
//|  ------------------------------------------------------------
/*|*/typedef struct 
/*|*/{
/*|*/    //|-----byte 0----|
/*|*/    unsigned char u4CSrcLen   :4;//表示RTP头部后面贡献源个数
/*|*/    unsigned char u1Externsion:1;//如果置1，在RTP Header会跟着一个header extension
/*|*/    unsigned char u1Padding   :1;//填充。如果置1，在packet的末尾被填充，填充有时是方便一些针对固定长度的算法的封装
/*|*/    unsigned char u2Version   :2;//RTP版本
/*|*/    //|-----byte 1----|
/*|*/    unsigned char u7Payload   :7;//表示所传输的多媒体的类型
/*|*/    unsigned char u1Marker    :1;
/*|*/    //|-----byte 2、3----|
/*|*/    unsigned short u16SeqNum;
/*|*/    //|-----byte 4~7----|
/*|*/    unsigned long u32TimeStamp;
/*|*/    //|-----byte 8~11----|
/*|*/    unsigned long u32SSrc;
/*|*/}L_STRUCT_RTPHEADER;
//|
//|  ------------------------------------------------------------
//|                 NaLu头
//|           +---------------+
//|           |0|1|2|3|4|5|6|7|
//|           +-+-+-+-+-+-+-+-+
//|           |F|NRI|  Type   |
//|           +---------------+
//|  其中，F为正常指示，NRI表示重要等级，Type表示NALU类型，比如0x65表示I帧。
//|  ------------------------------------------------------------
/*|*/typedef struct 
/*|*/{
/*|*/    unsigned char u5Type:5;
/*|*/    unsigned char u2Nri :2;
/*|*/    unsigned char u1F   :1;
/*|*/}L_STRUCT_RTP_NALUHEADER;
//|
//|  ------------------------------------------------------------
//|  RTP分片单元类型为FU-A:28；FU-B:29
//|  本程序采用的FU-A分片包结构为：
//|  (FU指示1Byte)+(FU头1Byte)+荷载+pad
//|  ------------------------------------------------------------
/*|*/typedef struct 
/*|*/{
/*|*/    unsigned char u5Type:5;//此类型为分片单元类型
/*|*/    unsigned char u2Nri:2;
/*|*/    unsigned char u1F:1;
/*|*/}L_STRUCT_RTP_FUA_INDICATOR;
//|
/*|*/typedef struct 
/*|*/{
/*|*/    unsigned char u5Type:5;//此类型为NaLu包类型
/*|*/    unsigned char u1R:1;
/*|*/    unsigned char u1E:1;
/*|*/    unsigned char u1S:1;
/*|*/}L_STRUCT_RTP_FUA_HEADER;
//|
//|  ------------------------------------------------------------
//|  为了使程序扩展起来更容易，在这里设置传入的数据类型
//|  这样后续在发送函数中针对不同类型的数据可以进行不同的操作
//|  RTP_H264对应的是裸流，含有起始码。
//|  RTP_H264NALU对应的是没有起始码的数据流。
//|  ------------------------------------------------------------
/*|*/typedef enum L_ENUM_RTP_SendPayload
/*|*/{
/*|*/    RTP_H264=0,
/*|*/    RTP_H264NALU,
/*|*/
/*|*/    RTP_NONE,
/*|*/}L_ENUM_RTPPAYLOAD;
//|
//|  ------------------------------------------------------------
//|  此结构体为使用本RTP例程的唯一结构体，兼具输入输出作用
//|  ------------------------------------------------------------
/*|*/typedef struct L_Struct_RTP_Session
/*|*/{
//|      ------------------------------------------------------------
//|      以下是关于初始化过程中需要的参数变量
//|      ------------------------------------------------------------
/*|*/    int                s32Sock;    //Socket描述符
/*|*/    struct sockaddr_in stDestAddr; //RTP传输对端地址，用于数据发送
/*|*/    unsigned int       u32SrcIP;   //本机IP地址，用于填充RTP首部，自动获取
/*|*/    unsigned int       u32DestIP;  //RTP传输对端IP，用于初始化，网络字节序
/*|*/    unsigned short     DestPort;   //RTP传输对端端口，用于初始化，主机字节序
/*|*/    struct ifreq       stIfreq;    //网络接口相关，用于获取本机IP地址以填充RTP首部
/*|*/    int                flag_inited;//初始化成功标志位
//|      ------------------------------------------------------------
//|      以下是仅发送过程中需要由调用函数设置的参数变量
//|      ------------------------------------------------------------
/*|*/    unsigned char     *pData;      //数据地址
/*|*/    int                DataLength; //数据长度
/*|*/    L_ENUM_RTPPAYLOAD  DataType;   //数据类型，例如H264
/*|*/    unsigned long long TimeStamp;  //时间戳
//|      ------------------------------------------------------------
//|      以下是仅发送过程中由发送函数设置的参数变量
//|      ------------------------------------------------------------
/*|*/    unsigned short     SequenceNum;//RTP序列号
/*|*/}L_STRUCT_RTPSESSION;
//+------------------------------------------------------------------------------------------+
//|                                       函数/变量声明
//+------------------------------------------------------------------------------------------+
/*|*/int L_RTP_CreateSession(L_STRUCT_RTPSESSION* RTPSession);
/*|*/int L_RTP_DestorySession(L_STRUCT_RTPSESSION* RTPSession);
/*|*/int L_RTP_Send(L_STRUCT_RTPSESSION* RTPSession);
//+------------------------------------------------------------------------------------------+

#endif
